// 模版字面量类型
type T = `abc`

// (带模版参数的)模版字面量类型
type T1 = `a${string}b`

// 将模版字符串用于其他类型表达式
// =============================================================================

// interface, object literal or alias types with index signature
type T2 = {
    [x: T1]: number // deny type T
    abc: 1
    accc: 2
    ab: 3
    add: 4
    cba: 5,
    abcs: false,
}

type P2 =  T2[T1] // support template with variables/parameters, but will precheck

// mapping, as index signature
type T3 = {
    [k in T1]: number
    // 'abc': 1 // deny
}

// keyof 
type U2 = keyof T2

type T4 = T3 & {
    abc: 1
    accc: 2
    ab: 3
    add: 4
    cba: 5,

}

type P6 = T4[T1]

// mapping with intersection
type T5 = {
    [k in keyof T4]: T4[k]
}

// A | B
type T6 = `a${string}c` | 'ab' | 'av' | 'ac' | 'abcc' // support and merged, type T6 = "ab" | `a${string}c` | "av"

// A & B
type T7 = `a${string}c` & 'abc' // support and converged, type T7 = "abc" 向具体类型收窄

// 将其它类型表达式用作模版参数
// =============================================================================
type U = 'a' | 'b'
type T10 = `a${U}b` // type T10 = "abb" | "aab"

type X = keyof T2 // keyof T 和 `...`总是安全的. typeof V, T[K], A & B 总是预先求值的. 映射与展开总是不兼容的
type T11 = `a${X}b` // 总是求值 X, 并确定X是否满足"模版参数"的条件

// 多模版参数的情况
// =============================================================================
// - 可以用正则表达式来表达()
// - 模版变量(类型): subtype of 'string | number | bigint | boolean | null | undefined | never'

// 1.如果string, number或bigint用作最后一个模版变量
type T201 = `a${string}b` // .*
type T202 = `a${number}b` // [0-9.]{1,}, more... ex: 112.2e3
// 如果是一个超过数字边界(超大的)的数字，那么它会被理解为number类型来参与匹配(也就是说, 数字的有效范围被一定程度上是忽略的)
let x1: T202 = 'a9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999b'
// bigint字面量会被作为一般数字类型解析(末尾没有n)
let x2: `a${bigint}b` = `a1134514b` 

// 2.与定界符或其它变量的交互作用
// - 字符串字面量和true/false/null/undefined总是作为"有限个确定字符的字符串(定界符)"去匹配
// - 在右侧没有有效"定界符(字面量)"的情况下, ${string}, ${bigint} 和 ${number} 有着额外的处理逻辑
// - ${string},${number},${bigint}和${infer X}都不能作为"定界符". 这使得他们
//      * 是最后一个模版变量时，就采用贪婪匹配(采用 .*)
//      * 右侧是非定界符时，就采用尽量少的匹配(采用 .)
//      * 右侧是定界且还有其他非定界时，就采用非贪婪匹配(采用 .*?)
type T21 = `a${U}    ${number}b` // (U1|U2|...|Un)
        // `a(U1|U2)${number}b`
type T22 = `a${string}XXX` // .*
        // `a.*       XXX`
type T23 = `a${string}${number}b` // .
        // `a.        ${number}b`
type T24 = `a${string}X${number}b` // .*? (非贪婪)
        // `a.*?      X${number}b`

let X22: T22 = `a123XXX`
let X23: T23 = `a123456b`
let X24: T24 = `a123X456b`

// 3. 0~3个字符
type CH_A = 'A'
type CH_B = 'B'
// ...
type CH_Z = 'Z'

type ToUnion<T extends string> = T extends `${infer U}${infer V}` ? U | ToUnion<V> : never

type S = 'abcdefghijklmnopqrstuvwxyz'
type S_U = ToUnion<S> // 'a' | 'b' | 'c' | ... | 'z'




